import * as cron from 'node-cron';
import prisma from '@/utils/db/PrismaService';
import { getCurrentTimeInShanghai } from '@/utils/storage';
import axios from 'axios';

// 定时任务类型接口
interface TimerTask {
  id: number;
  task_name: string;
  task_code: string;
  cron_expression: string;
  task_type: string;
  task_config?: string | null;
  description?: string | null;
  status: number;
}

// 任务执行结果接口
interface TaskExecuteResult {
  success: boolean;
  result?: any;
  errorMsg?: string;
  costTime: number;
}

/**
 * 定时任务管理器
 * 单例模式，管理所有定时任务
 */
export class TimerTaskManager {
  private static instance: TimerTaskManager;
  private tasks: Map<number, cron.ScheduledTask> = new Map();
  private executingTasks: Set<number> = new Set(); // 记录正在执行的任务ID
  private isInitialized = false;

  private constructor() {}

  /**
   * 获取单例实例
   */
  static getInstance(): TimerTaskManager {
    if (!TimerTaskManager.instance) {
      TimerTaskManager.instance = new TimerTaskManager();
    }
    return TimerTaskManager.instance;
  }

  /**
   * 初始化定时任务管理器
   * 从数据库加载所有启用的任务并启动
   */
  async initialize(): Promise<void> {
    if (this.isInitialized) {
      return;
    }

    try {
      
      // 从数据库加载所有启用的定时任务
      const activeTasks = await prisma.sysTimerTask.findMany({
        where: {
          status: 1, // 启用状态
          del_flag: 1 // 未删除
        }
      });


      // 启动所有启用的任务
      let successCount = 0;
      for (const task of activeTasks) {
        const success = this.startTask(task as TimerTask);
        if (success) {
          successCount++;
        }
      }

      this.isInitialized = true;
    } catch (error) {
      console.error('初始化定时任务管理器失败:', error);
      // 即使初始化失败，也标记为已初始化，避免重复尝试
      this.isInitialized = true;
    }
  }

  /**
   * 启动定时任务
   */
  startTask(task: TimerTask): boolean {
    try {
      // 如果任务已存在，先停止
      if (this.tasks.has(task.id)) {
        this.stopTask(task.id);
      }

      // 验证cron表达式
      if (!cron.validate(task.cron_expression)) {
        console.error(`任务 ${task.task_name} 的cron表达式无效: ${task.cron_expression}`);
        return false;
      }

      // 创建定时任务
      const scheduledTask = cron.schedule(task.cron_expression, async () => {
        await this.executeTask(task);
      }, {
        scheduled: true,
        timezone: 'Asia/Shanghai'
      });

      // 保存任务
      this.tasks.set(task.id, scheduledTask);
      
      console.log(`定时任务已启动: ${task.task_name} (${task.cron_expression})`);
      return true;
    } catch (error) {
      console.error(`启动定时任务失败: ${task.task_name}`, error);
      return false;
    }
  }

  /**
   * 停止定时任务
   */
  stopTask(taskId: number): boolean {
    try {
      const task = this.tasks.get(taskId);
      if (task) {
        task.stop();
        // node-cron的ScheduledTask没有destroy方法，只需要stop
        this.tasks.delete(taskId);
        console.log(`定时任务已停止: ID ${taskId}`);
        return true;
      }
      return false;
    } catch (error) {
      console.error(`停止定时任务失败: ID ${taskId}`, error);
      return false;
    }
  }

  /**
   * 执行定时任务
   */
  async executeTask(task: TimerTask): Promise<TaskExecuteResult> {
    const startTime = Date.now();
    const executeTime = getCurrentTimeInShanghai();
    
    try {
      // 标记任务开始执行
      this.executingTasks.add(task.id);
      
      // 检查任务是否仍然存在于数据库中（防止已删除的任务继续执行）
      const currentTask = await prisma.sysTimerTask.findUnique({
        where: { id: task.id, del_flag: 1 }
      });
      
      if (!currentTask || currentTask.status !== 1) {
        console.log(`任务 ${task.task_name} 已被删除或禁用，跳过执行`);
        // 从调度器中移除该任务
        this.stopTask(task.id);
        return {
          success: false,
          errorMsg: '任务已被删除或禁用',
          costTime: 0
        };
      }
      
      console.log(`开始执行定时任务: ${task.task_name}`);

      let result: any;

      // 根据任务类型执行不同的逻辑
      switch (task.task_type) {
        case 'api_call':
          result = await this.executeApiCall(task);
          break;
          
        case 'database_cleanup':
          result = await this.executeDatabaseCleanup(task);
          break;
          
        case 'data_sync':
          result = await this.executeDataSync(task);
          break;
          
        case 'report_generate':
          result = await this.executeReportGenerate(task);
          break;
          
        case 'system_monitor':
          result = await this.executeSystemMonitor(task);
          break;
          
        case 'custom':
          result = await this.executeCustomScript(task);
          break;
          
        case 'javascript':
          result = await this.executeJavaScriptCode(task);
          break;
          
        default:
          throw new Error(`不支持的任务类型: ${task.task_type}`);
      }

      const costTime = Date.now() - startTime;

      // 记录执行日志
      await this.logTaskExecution(task.id, executeTime, 1, result, null, costTime);

      // 更新任务信息
      await this.updateTaskInfo(task.id, executeTime, costTime);

      console.log(`定时任务执行成功: ${task.task_name}, 耗时: ${costTime}ms`);
      
      return {
        success: true,
        result,
        costTime
      };

    } catch (error: any) {
      const costTime = Date.now() - startTime;
      const errorMsg = error.message || '执行失败';

      // 记录错误日志
      await this.logTaskExecution(task.id, executeTime, 0, null, errorMsg, costTime);

      console.error(`定时任务执行失败: ${task.task_name}`, error);
      
      return {
        success: false,
        errorMsg,
        costTime
      };
    } finally {
      // 执行完成后移除执行标记
      this.executingTasks.delete(task.id);
    }
  }

  /**
   * 执行API调用任务
   */
  private async executeApiCall(task: TimerTask): Promise<any> {
    if (!task.task_config) {
      throw new Error('API调用任务缺少配置信息');
    }

    const config = JSON.parse(task.task_config);
    const { url, method = 'GET', headers = {}, data } = config;

    if (!url) {
      throw new Error('API调用任务缺少URL配置');
    }

    const response = await axios({
      url,
      method,
      headers,
      data,
      timeout: 30000 // 30秒超时
    });

    return {
      status: response.status,
      statusText: response.statusText,
      data: response.data
    };
  }

  /**
   * 执行数据库清理任务
   */
  private async executeDatabaseCleanup(task: TimerTask): Promise<any> {
    if (!task.task_config) {
      throw new Error('数据库清理任务缺少配置信息');
    }

    const config = JSON.parse(task.task_config);
    const { table, days } = config;

    if (!table) {
      throw new Error('数据库清理任务缺少表名配置');
    }

    let result;
    
    if (table === 'sys_log' && days) {
      // 清理系统日志
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - parseInt(days));
      
      result = await prisma.$executeRaw`
        DELETE FROM sys_log 
        WHERE operation_time < ${cutoffDate}
      `;
    } else if (table === 'sys_timer_log' && days) {
      // 清理定时任务日志
      const cutoffTime = getCurrentTimeInShanghai().substring(0, 10);
      const cutoffDate = new Date(cutoffTime);
      cutoffDate.setDate(cutoffDate.getDate() - parseInt(days));
      
      result = await prisma.$executeRaw`
        DELETE FROM sys_timer_log 
        WHERE execute_time < ${cutoffDate.toISOString().substring(0, 10)}
      `;
    } else {
      throw new Error('不支持的数据库清理配置');
    }

    return { deletedCount: result };
  }

  /**
   * 执行数据同步任务
   */
  private async executeDataSync(task: TimerTask): Promise<any> {
    // 这里可以实现具体的数据同步逻辑
    return { message: '数据同步任务执行完成' };
  }

  /**
   * 执行报表生成任务
   */
  private async executeReportGenerate(task: TimerTask): Promise<any> {
    // 这里可以实现具体的报表生成逻辑
    return { message: '报表生成任务执行完成' };
  }

  /**
   * 执行系统监控任务
   */
  private async executeSystemMonitor(task: TimerTask): Promise<any> {
    // 这里可以实现具体的系统监控逻辑
    const memoryUsage = process.memoryUsage();
    const uptime = process.uptime();
    
    return {
      memory: memoryUsage,
      uptime,
      timestamp: getCurrentTimeInShanghai()
    };
  }

  /**
   * 执行自定义Shell脚本任务
   */
  private async executeCustomScript(task: TimerTask): Promise<any> {
    if (!task.task_config) {
      throw new Error('自定义脚本任务缺少配置信息');
    }

    const config = JSON.parse(task.task_config);
    const { path, args = [], workingDir, timeout = 30000 } = config;
    
    if (!path) {
      throw new Error('Shell 脚本路径不能为空');
    }

    const { exec } = require('child_process');
    const { promisify } = require('util');
    const execAsync = promisify(exec);

    try {
      const command = `${path} ${args.join(' ')}`;
      const options: any = { timeout };
      
      if (workingDir) {
        options.cwd = workingDir;
      }

      console.log(`[定时任务] ${task.task_name}: 执行Shell脚本: ${command}`);
      const { stdout, stderr } = await execAsync(command, options);
      
      return {
        type: 'shell',
        stdout: stdout.trim(),
        stderr: stderr.trim(),
        command,
        timestamp: getCurrentTimeInShanghai()
      };
    } catch (error: any) {
      throw new Error(`Shell 脚本执行失败: ${error.message}`);
    }
  }

  /**
   * 执行 JavaScript 代码任务
   */
  private async executeJavaScriptCode(task: TimerTask): Promise<any> {
    if (!task.task_config) {
      throw new Error('JavaScript 任务缺少配置信息');
    }

    let config: any;
    let code: string;

    try {
      // 尝试解析JSON配置
      if (typeof task.task_config === 'string') {
        config = JSON.parse(task.task_config);
      } else {
        config = task.task_config;
      }
      
      console.log(`[定时任务] ${task.task_name}: 解析后配置:`, config);
      
      // 提取代码
      if (config.code) {
        code = config.code;
      } else if (typeof config === 'string') {
        // 如果config本身就是代码字符串
        code = config;
      } else {
        throw new Error('配置中没有找到code字段');
      }
      
    } catch (parseError: any) {
      // 如果JSON解析失败，尝试直接使用原始字符串作为代码
      console.log(`[定时任务] ${task.task_name}: JSON解析失败，尝试直接使用原始字符串:`, parseError.message);
      if (typeof task.task_config === 'string') {
        code = task.task_config;
      } else {
        throw new Error(`配置解析失败: ${parseError.message}`);
      }
    }

    if (!code || code.trim() === '') {
      throw new Error(`JavaScript 代码不能为空。当前代码: "${code}"`);
    }

    // console.log(`[定时任务] ${task.task_name}: 准备执行代码:`, code);

    try {
      // 创建一个安全的执行环境
      const context = {
        console: {
          log: (...args: any[]) => {
            console.log('[定时任务]', task.task_name, ':', ...args);
            return args.join(' ');
          },
          error: (...args: any[]) => {
            console.error('[定时任务]', task.task_name, ':', ...args);
            return args.join(' ');
          },
          warn: (...args: any[]) => {
            console.warn('[定时任务]', task.task_name, ':', ...args);
            return args.join(' ');
          }
        },
        Date,
        Math,
        JSON,
        setTimeout,
        clearTimeout,
        // 添加一些常用的 Node.js 模块
        require: (moduleName: string) => {
          // 只允许一些安全的模块
          const allowedModules = ['fs', 'path', 'os', 'crypto'];
          if (allowedModules.includes(moduleName)) {
            return require(moduleName);
          }
          throw new Error(`模块 ${moduleName} 不被允许`);
        }
      };

      // 创建函数并执行
      const func = new Function('context', `
        const { console, Date, Math, JSON, setTimeout, clearTimeout, require } = context;
        let result;
        ${code}
        return result;
      `);

      const result = func(context);
      
      return {
        type: 'javascript',
        result: result || 'JavaScript 代码执行完成',
        timestamp: getCurrentTimeInShanghai()
      };
    } catch (error: any) {
      throw new Error(`JavaScript 代码执行失败: ${error.message}`);
    }
  }



  /**
   * 记录任务执行日志
   */
  private async logTaskExecution(
    taskId: number,
    executeTime: string,
    status: number,
    result: any,
    errorMsg: string | null,
    costTime: number
  ): Promise<void> {
    try {
      // 使用原生SQL避免Prisma客户端生成问题
      await prisma.$executeRaw`
        INSERT INTO sys_timer_log (task_id, execute_time, status, result, error_msg, cost_time)
        VALUES (${taskId}, ${executeTime}, ${status}, ${result ? JSON.stringify(result) : null}, ${errorMsg}, ${costTime})
      `;
    } catch (error) {
      console.error('记录任务执行日志失败:', error);
    }
  }

  /**
   * 更新任务信息
   */
  private async updateTaskInfo(taskId: number, lastRunTime: string, costTime: number): Promise<void> {
    try {
      const nextRunTime = TimerTaskManager.getNextRunTime('0 * * * *'); // 简化实现
      
      await prisma.$executeRaw`
        UPDATE sys_timer_task 
        SET last_run_time = ${lastRunTime}, 
            next_run_time = ${nextRunTime},
            run_count = run_count + 1,
            update_time = ${getCurrentTimeInShanghai()}
        WHERE id = ${taskId}
      `;
    } catch (error) {
      console.error('更新任务信息失败:', error);
    }
  }

  /**
   * 验证cron表达式
   */
  static validateCronExpression(expression: string): boolean {
    return cron.validate(expression);
  }

  /**
   * 获取下次执行时间
   */
  static getNextRunTime(cronExpression: string): string {
    try {
      // 简化实现，返回当前时间+1小时
      const now = new Date();
      now.setHours(now.getHours() + 1);
      return now.toISOString().replace('T', ' ').substring(0, 19);
    } catch (error) {
      return '';
    }
  }

  /**
   * 获取当前运行的任务数量
   */
  getRunningTaskCount(): number {
    return this.tasks.size;
  }

  /**
   * 获取所有运行中的任务ID
   */
  getRunningTaskIds(): number[] {
    return Array.from(this.tasks.keys());
  }

  /**
   * 检查任务是否正在执行
   */
  isTaskExecuting(taskId: number): boolean {
    return this.executingTasks.has(taskId);
  }

  /**
   * 获取所有正在执行的任务ID
   */
  getExecutingTaskIds(): number[] {
    return Array.from(this.executingTasks);
  }

  /**
   * 停止所有任务
   */
  stopAllTasks(): void {
    for (const [taskId, task] of this.tasks) {
      try {
        task.stop();
      } catch (error) {
        console.error(`停止任务 ${taskId} 失败:`, error);
      }
    }
    this.tasks.clear();
    console.log('所有定时任务已停止');
  }
} 